package LiuYun

import spinal.core._
import spinal.lib._

class CsrWb extends Bundle{
    val va   :UInt = LISA.GPR
    val pc   :UInt = LISA.GPR 
    val ex   :Bool = Bool()
    val ecode:UInt = LISA.Ex.Code
    val esubc:UInt = LISA.Ex.Subc
    val ertn :Bool = Bool()
    val ll   :Bool = Bool()
    val sc   :Bool = Bool()
    def isRefill = ex && ecode === LISA.Ex.TLBR.code
    def isMemEx  = ex && LISA.Ex.isMem(ecode)
    def isTlbEx  = ex && LISA.Ex.isTlb(ecode)
    def gen_cancel(csr:Csr,exbus:CoreCancel){
        exbus.cancel := ex || ertn
        when(ex){
            exbus.target := Mux(isRefill,csr.tlbrentry.pa,csr.eentry.va) << 6
        }.otherwise{
            exbus.target := csr.era.pc
        }
    }
}
class StageWb extends Component{
    val io = new Bundle{
        val ic:PipeCtrl = slave(new PipeCtrl)
        val idat:SDatWb = in(new SDatWb)
        val fw:Forwarding = out(new Forwarding)
        val grw:RFWrite = out(new RFWrite)
        val tocsr:CsrWb = out(new CsrWb)
        val debug:CoreDebug = out(new CoreDebug)
        val difftest_load:DiffLoad = out(new DiffLoad)
        val difftest_store:DiffStore = out(new DiffStore)
        val difftest_inst:DiffInst = out(new DiffInst(LISA.w_tlbidx))
        val difftest_excp:DiffExcp = out(new DiffExcp)
        val difftest_trap:DiffTrap = out(new DiffTrap)
        //val sc_w:Bool = out(Bool())
    }
    io.fw.valid := io.ic.valid
    io.fw.grwr  := io.idat.grwr
    io.fw.dest  := io.idat.dest
    io.fw.block := False
    io.fw.value := io.idat.value
    io.ic.allow := True
    io.ic.empty := True

    val grwr:Bool = io.ic.valid && io.idat.grwr && !io.ic.ex
    io.grw.en   := grwr
    io.grw.addr := io.idat.dest
    io.grw.data := io.idat.value
   
    io.tocsr.va := io.idat.va
    io.tocsr.pc := io.idat.pc
    io.tocsr.ex := io.ic.ex
    io.tocsr.ecode := io.idat.ecode
    io.tocsr.esubc := io.idat.esubc
    io.tocsr.ll    := io.ic.valid && Instructions.isInst(io.idat.inst, "LL.W")
    io.tocsr.sc    := io.ic.valid && Instructions.isInst(io.idat.inst, "SC.W")
    io.tocsr.ertn  := io.ic.valid && io.idat.itype.is_ertn

    io.debug.pc       := io.idat.pc
    io.debug.rf_wen   := Mux(grwr, U"1111", U(0))
    io.debug.rf_wnum  := io.idat.dest
    io.debug.rf_wdata := io.idat.value

    io.difftest_load.coreid := B(0,8 bits)
    io.difftest_load.index := B(0,8 bits)
    io.difftest_load.valid := RegNext(B(0,2 bits)##io.tocsr.ll##io.idat.difftest_load)
    io.difftest_load.paddr := RegNext(io.idat.pa(31 downto 12)@@io.idat.va(11 downto 0)) //pa low bits exist bug
    io.difftest_load.vaddr := RegNext(io.idat.va)

    io.difftest_store.coreid := B(0,8 bits)
    io.difftest_store.index := B(0,8 bits)
    io.difftest_store.valid := RegNext(B(0,5 bits)##((io.idat.difftest_store)&((~io.tocsr.ex)##(~io.tocsr.ex)##(~io.tocsr.ex)))) //need re-assign llbit
    io.difftest_store.storePAddr := RegNext(io.idat.pa(31 downto 12)@@io.idat.va(11 downto 0)) //pa low bits exist bug
    io.difftest_store.storeVAddr := RegNext(io.idat.va)
    io.difftest_store.storeData := RegNext(io.idat.wdata.asBits)

    io.difftest_inst.coreid := B(0,8 bits)
    io.difftest_inst.index := B(0,8 bits)
    io.difftest_inst.valid := RegNext(io.ic.valid && !io.ic.ex)
    io.difftest_inst.pc := RegNext(io.idat.pc)
    io.difftest_inst.instr := RegNext(io.idat.inst.asBits)
    io.difftest_inst.skip := False
    io.difftest_inst.is_TLBFILL := RegNext(io.ic.valid && Instructions.isInst(io.idat.inst, "TLBFILL"))
    io.difftest_inst.TLBFILL_index := RegNext(io.idat.tlbfill_index)
    io.difftest_inst.is_CNTinst := RegNext(Instructions.isInst(io.idat.inst, "RDCNTID.W") || Instructions.isInst(io.idat.inst, "RDCNTVL.W") || Instructions.isInst(io.idat.inst, "RDCNTVH.W"))
    io.difftest_inst.timer_64_value := RegNext(io.idat.tv)
    io.difftest_inst.wen := RegNext(io.grw.en)
    io.difftest_inst.wdest := RegNext(io.grw.addr)
    io.difftest_inst.wdata := RegNext(io.grw.data)
    io.difftest_inst.csr_rstat :=  RegNext((Instructions.isInst(io.idat.inst, "CSRRD") || Instructions.isInst(io.idat.inst, "CSRWR") || Instructions.isInst(io.idat.inst, "CSRXCHG")) && io.idat.inst(23 downto 10) === U(5,14 bits))
    io.difftest_inst.csr_data := RegNext(io.idat.csr_estat)

    io.difftest_excp.coreid := B(0,8 bits)
    io.difftest_excp.excp_valid := RegNext(io.tocsr.ex)
    io.difftest_excp.eret := RegNext(io.tocsr.ertn)
    io.difftest_excp.intrNo := RegNext(io.idat.csr_estat(12 downto 2))
    io.difftest_excp.cause := RegNext(io.idat.ecode.asBits)
    io.difftest_excp.exceptionPC := RegNext(io.idat.pc)
    io.difftest_excp.exceptionInst := RegNext(io.idat.inst)

    io.difftest_trap.coreid := B(0,8 bits)
    io.difftest_trap.valid := False
    io.difftest_trap.code := U(0,8 bits)
    io.difftest_trap.pc := io.idat.pc.asBits
    io.difftest_trap.cycleCnt := U(0,64 bits)
    io.difftest_trap.instrCnt := U(0,64 bits)
    
}
